home *** CD-ROM | disk | FTP | other *** search
/ W95 Shareware Collection / W95 Collection - Windows 95 Shareware (LCDCAN).iso / win95 / programm / heap32 / heap32.c next >
Encoding:
C/C++ Source or Header  |  1994-12-06  |  27.6 KB  |  597 lines

  1. /******************************************************************************
  2. *                                                                             *
  3. *                   Heap walk utility - 12/4/94 by Mark Gamber                *
  4. *                                                                             *
  5. ******************************************************************************/
  6.  
  7. #include "windows.h"
  8. #include "tlhelp32.h"
  9.  
  10. // === Function Prototypes ====================================================
  11.                                                  //  The program "walking tour"
  12. LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM, LPARAM );       //  Main window
  13. BOOL WINAPI AboutDlgProc( HWND, UINT, WPARAM, LPARAM );          //  Beavis box
  14. BOOL InitApplication( HINSTANCE, int );        //  Register class, start window
  15. BOOL CreateChildWindows( HWND );                           //  Create listboxes
  16. BOOL ResizeChildWindows( HWND );       //  Resize listboxe when parent is sized
  17. BOOL ListProcesses( HWND );                               //  Walk process list
  18. BOOL FindModuleByID( DWORD, DWORD, char * );  //  Get module name by Process ID
  19. BOOL ListProcessHeap( HWND, DWORD );                    //  Walk process's heap
  20. BOOL WINAPI DataDlgProc( HWND, UINT, WPARAM, LPARAM );     //  Contents display
  21.  
  22. // === Global Variables =======================================================
  23.  
  24. HINSTANCE hInst;                                       //  Application instance
  25. HWND hMainWnd;                                           //  Main window handle
  26. HFONT hFont;                                        //  Font used for listboxes
  27. HBRUSH hBrush;                                     //  Brush used for listboxes
  28. HWND hLastFocus;                                  //  Last listbox to get focus
  29.  
  30. // === Application Entry Point ================================================
  31.  
  32. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd,
  33.                       int nShow )
  34. {
  35.    MSG msg;
  36.  
  37.    if( ! InitApplication( hInstance, nShow ) )         //  If ya can't start it
  38.       return( FALSE );                                      //  ya can't run it
  39.  
  40.    while( GetMessage( &msg, NULL, 0, 0 ) )            //  Do that message thang
  41.    {
  42.       if( IsDialogMessage( hMainWnd, &msg ) )    //  Makes TAB work on a window
  43.          continue;                                       //  to change controls
  44.  
  45.       TranslateMessage( &msg );             //  If not some dialog thing, do it
  46.       DispatchMessage( &msg );                        //  the old fashioned way
  47.    }
  48.  
  49.    DeleteObject( hFont );                  //  Kill these things on the way out
  50.    DeleteObject( hBrush );
  51.    return( FALSE );
  52. }                                                          //  End of WinMain()
  53.  
  54. // === Main Window Procedure ==================================================
  55.  
  56. LRESULT WINAPI MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  57. {
  58.    switch( msg )
  59.    {
  60.       case WM_CREATE:
  61.          if( ! CreateChildWindows( hWnd ) )         //  Create child windows or
  62.             return( -1 );                    //  there's no point in proceeding
  63.          ListProcesses( GetDlgItem( hWnd, 10 ) );     //  List processes (hey!)
  64.          hLastFocus = GetDlgItem( hWnd, 10 );         //  Process box has focus
  65.          break;
  66.  
  67.  
  68.       case WM_DESTROY:
  69.          PostQuitMessage( 0 );               //  Kill app when window is killed
  70.          break;
  71.  
  72.  
  73.       case WM_SIZE:                     //  Resize listboxes when this is sized
  74.          ResizeChildWindows( hWnd );
  75.          break;
  76.  
  77.  
  78.       case WM_CTLCOLORLISTBOX:          //  Color listbox with focus light blue
  79.          if( hLastFocus == (HWND)lParam )    //  Is this listbox same as focus?
  80.          {                                                  //  If so, color it
  81.             SetBkColor( (HDC)wParam, RGB( 0, 255, 255 ) );
  82.             return( (LRESULT)hBrush );
  83.          }
  84.          break;                     //  Else, let Windows have it's way with it
  85.  
  86.  
  87.       case WM_COMMAND:
  88.       {
  89.          if( HIWORD( wParam ) == LBN_SETFOCUS )   // Set colors on focus change
  90.          {
  91.             if( LOWORD( wParam ) == 10 || LOWORD( wParam ) == 11 )
  92.             {
  93.                hLastFocus = (HWND)lParam;        //  Save new window with focus
  94.                InvalidateRect( GetDlgItem( hWnd, 10 ), NULL, TRUE );  //  Force
  95.                InvalidateRect( GetDlgItem( hWnd, 11 ), NULL, TRUE ); //  redraw
  96.             }
  97.             else                    //  If on a header, put onto a data listbox
  98.                SetFocus( GetDlgItem( hWnd, LOWORD( wParam ) + 2 ) );
  99.  
  100.             break;
  101.          }
  102.          
  103.          if( wParam == 100 )                  //  "Update - Processes" selected
  104.          {                                                //  Walk process list
  105.             ListProcesses( GetDlgItem( hWnd, 10 ) );  
  106.             SetFocus( GetDlgItem( hWnd, 10 ) );      //  Give process box focus
  107.             break;
  108.          }
  109.  
  110.          if( wParam == 101 ||         //  "Update-Heap" or process double-click
  111.              ( HIWORD( wParam ) == LBN_DBLCLK && 
  112.                LOWORD( wParam ) == 10 ) )                //  on process listbox
  113.          {
  114.             int iItem;
  115.             DWORD dwProcID;
  116.                                           //  Get current process box selection
  117.             iItem = SendDlgItemMessage( hWnd, 10, LB_GETCURSEL, 0, 0 );
  118.             if( iItem == LB_ERR )
  119.             {                                     //  Tell user if no selection
  120.                MessageBox( hWnd, "No Process has been selected!",
  121.                            "Heap32", MB_OK | MB_ICONEXCLAMATION );
  122.                break;
  123.             }                   //  Get proc ID stored as item data when walked
  124.             dwProcID = SendDlgItemMessage( hWnd, 10, LB_GETITEMDATA,
  125.                                            iItem, 0 );
  126.             if( dwProcID )                            //  If seemingly valid...
  127.             {                                //  Display heap for given process
  128.                ListProcessHeap( GetDlgItem( hWnd, 11 ), dwProcID );
  129.                SetFocus( GetDlgItem( hWnd, 11 ) );      //  Heap box gets focus
  130.             }
  131.             break;
  132.          }
  133.          if( wParam == 102 ||                //  Want to display item contents?
  134.              ( HIWORD( wParam ) == LBN_DBLCLK && 
  135.                LOWORD( wParam ) == 11 ) )
  136.          {
  137.             int iItem;
  138.                                                       //  Get current heap item
  139.             iItem = SendDlgItemMessage( hWnd, 11, LB_GETCURSEL, 0, 0 );
  140.             if( iItem == LB_ERR )          //  Tell user if nothing is selected
  141.             {
  142.                MessageBox( hWnd, "No data item has been selected!",
  143.                            "Heap32", MB_OK | MB_ICONEXCLAMATION );
  144.                break;
  145.             }
  146.                                      //  Call display dialog, passing selection
  147.             DialogBoxParam( hInst, MAKEINTRESOURCE( 10001 ), hWnd,
  148.                             DataDlgProc, iItem );
  149.             break;
  150.          }
  151.          if( wParam == 200 )
  152.          {
  153.             DestroyWindow( hWnd );                              //  Die on exit
  154.             break;
  155.          }
  156.          if( wParam == 201 )
  157.          {                    //  The Hokey Pokey is what it's really all about
  158.             DialogBox( hInst, MAKEINTRESOURCE( 10000 ), hWnd,
  159.                        AboutDlgProc );
  160.             break;
  161.          }
  162.          break;
  163.       }                                                   //  End of WM_COMMAND
  164.  
  165.  
  166.       default:
  167.          return( DefWindowProc( hWnd, msg, wParam, lParam ) );
  168.    }
  169.    return( FALSE );
  170. }                                                      //  End of MainWndProc()
  171.  
  172. // === Register classes and Start Top Level Window ============================
  173.  
  174. BOOL InitApplication( HINSTANCE hInstance, int nShow )
  175. {
  176.    WNDCLASSEX wc;
  177.  
  178.    wc.cbSize = sizeof(WNDCLASSEX);
  179.    wc.style = 0;
  180.    wc.lpfnWndProc = MainWndProc;                             //  Register class
  181.    wc.lpszClassName = "PEEPS32";                              //  Hiya Pradeep!
  182.    wc.lpszMenuName = "MainMenu";
  183.    wc.hInstance = hInstance;
  184.    wc.hIcon = LoadImage( hInstance, MAKEINTRESOURCE( 100 ), IMAGE_ICON,
  185.                          32, 32, LR_DEFAULTCOLOR );
  186.    wc.hIconSm = LoadImage( hInstance, MAKEINTRESOURCE( 100 ), IMAGE_ICON,
  187.                            16, 16, LR_DEFAULTCOLOR );
  188.    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  189.    wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
  190.    wc.cbClsExtra = 0;
  191.    wc.cbWndExtra = 0;
  192.  
  193.    if( ! RegisterClassEx( &wc ) )//  Quit if register fails
  194.       return( FALSE );
  195.  
  196.    hInst = hInstance;                                //  Create the main window
  197.    hMainWnd = CreateWindow( "PEEPS32", "Heap32", WS_OVERLAPPEDWINDOW,
  198.                             CW_USEDEFAULT, CW_USEDEFAULT,
  199.                             300, 216, NULL, NULL, hInstance, NULL );
  200.    if( ! hMainWnd )
  201.       return( FALSE );                            //  Fail if main window fails
  202.                                                          //  Create focus brush
  203.    hBrush = CreateSolidBrush( RGB( 0, 255, 255 ) );     //  killed in WinMain()
  204.  
  205.    ShowWindow( hMainWnd, nShow );         //  Display main window and we're set
  206.    UpdateWindow( hMainWnd );
  207.                                                        //  Use a small font and
  208.    hFont = CreateFont( -8, 0, 0, 0, FW_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0,
  209.                        "MS Sans Serif" );
  210.                                               //  Apply it to all the listboxes
  211.    SendDlgItemMessage( hMainWnd, 8, WM_SETFONT, (WPARAM)hFont, 1 );
  212.    SendDlgItemMessage( hMainWnd, 9, WM_SETFONT, (WPARAM)hFont, 1 );
  213.    SendDlgItemMessage( hMainWnd, 10, WM_SETFONT, (WPARAM)hFont, 1 );
  214.    SendDlgItemMessage( hMainWnd, 11, WM_SETFONT, (WPARAM)hFont, 1 );
  215.    return( TRUE );
  216. }                                                  //  End of InitApplication()
  217.  
  218. // === Create Child Listboxes for the Main Window =============================
  219.  
  220. BOOL CreateChildWindows( HWND hWnd )
  221. {
  222.    HWND hNew;
  223.    RECT Rect;
  224.    int iSep[ 3 ];
  225.  
  226.                                                 //  Get size of the main window
  227.    GetClientRect( hWnd, &Rect );                    //  Create a header listbox
  228.    hNew = CreateWindow( "listbox", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE |
  229.                         LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS,
  230.                         0, 0, Rect.right, 14, hWnd, (HMENU)8, hInst, NULL );
  231.    if( ! hNew )
  232.       return( FALSE );                               //  If listbox fails, exit
  233.    
  234.    iSep[ 0 ] = 60;                                         //  Add one tab stop
  235.    SendMessage( hNew, LB_SETTABSTOPS, 1, (LPARAM)iSep );
  236.    SendMessage( hNew, LB_ADDSTRING, 0,                      //  Add header text
  237.                 (LPARAM)"Process Name\tProcess ID" );
  238.    SendMessage( hNew, LB_SETCURSEL, 0, 0 );
  239.                           
  240.                           //  Now create the process listbox (dig them styles!)
  241.    hNew = CreateWindow( "listbox", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE |
  242.                         LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
  243.                         LBS_USETABSTOPS | WS_TABSTOP,
  244.                         0, 14, Rect.right, ( Rect.bottom / 2 ) - 14,
  245.                         hWnd, (HMENU)10, hInst, NULL );
  246.    if( ! hNew )
  247.       return( FALSE );                             //  Set a tab stop here, too
  248.    SendMessage( hNew, LB_SETTABSTOPS, 1, (LPARAM)iSep );
  249.                                                  //  Create heap header listbox
  250.    hNew = CreateWindow( "listbox", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE |
  251.                         LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS,
  252.                         0, ( Rect.bottom / 2 ) + 2,
  253.                         Rect.right, 14, hWnd, (HMENU)9, hInst, NULL );
  254.    if( ! hNew )
  255.       return( FALSE );
  256.  
  257.    iSep[ 0 ] = 36;                            //  This needs three tab settings
  258.    iSep[ 1 ] = 66;
  259.    iSep[ 2 ] = 96;
  260.    SendMessage( hNew, LB_SETTABSTOPS, 3, (LPARAM)iSep );
  261.  
  262.    SendMessage( hNew, LB_ADDSTRING, 0,                 //  Set heap header text
  263.                 (LPARAM)"Handle\tAddress\tSize\tFlags" );
  264.    SendMessage( hNew, LB_SETCURSEL, 0, 0 );
  265.                                                 //  and create the heap listbox
  266.    hNew = CreateWindow( "listbox", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE |
  267.                         LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
  268.                         LBS_USETABSTOPS | WS_TABSTOP,
  269.                         0, ( Rect.bottom / 2 ) + 16, 
  270.                         Rect.right, ( Rect.bottom / 2 ) - 16,
  271.                         hWnd, (HMENU)11, hInst, NULL );
  272.  
  273.    if( ! hNew )
  274.       return( FALSE );
  275.                                                      //  Set tabstops here, too
  276.    SendMessage( hNew, LB_SETTABSTOPS, 3, (LPARAM)iSep );
  277.    SetFocus( GetDlgItem( hWnd, 10 ) );          //  Process box has focus first
  278.    return( TRUE );
  279. }                                               //  End of CreateChildWindows()
  280.  
  281. // === Resize Listboxes When Main Window is Resized ===========================
  282.  
  283. BOOL ResizeChildWindows( HWND hWnd )
  284. {
  285.    RECT Rect;
  286.    HDWP hDwp;
  287.  
  288.  
  289.    GetClientRect( hWnd, &Rect );
  290.    hDwp = BeginDeferWindowPos( 4 );             //  Make it look nice, use this
  291.  
  292.    DeferWindowPos( hDwp, GetDlgItem( hWnd, 8 ), NULL,         //  Resize header
  293.                    0, 0, Rect.right, 14, SWP_NOZORDER );
  294.  
  295.    DeferWindowPos( hDwp, GetDlgItem( hWnd, 10 ), NULL,       //  Resize process
  296.                    0, 14,                                        //  ID listbox
  297.                    Rect.right, ( Rect.bottom / 2 ) - 16,
  298.                    SWP_NOZORDER );
  299.  
  300.    DeferWindowPos( hDwp, GetDlgItem( hWnd, 9 ), NULL,    //  Resize heap header
  301.                    0, ( Rect.bottom / 2 ) + 2, 
  302.                    Rect.right, 14, SWP_NOZORDER );
  303.    
  304.    DeferWindowPos( hDwp, GetDlgItem( hWnd, 11 ), NULL,  //  Resize heap listbox
  305.                    0, ( Rect.bottom / 2 ) + 16,
  306.                    Rect.right, ( Rect.bottom / 2 ) - 16,
  307.                    SWP_NOZORDER );
  308.    EndDeferWindowPos( hDwp );                                    // Let 'em fly
  309.    return( TRUE );
  310. }                                               //  End of ResizeChildWindows()
  311.  
  312. // === Display Running Processes in a Listbox =================================
  313.  
  314. BOOL ListProcesses( HWND hListbox )
  315. {
  316.    HANDLE hMemShot;
  317.    PROCESSENTRY32 pe;
  318.    BOOL bStatus;
  319.    char szStr[ 256 ];
  320.    int iItem;
  321.  
  322.                                              //  Take a picture of Win32 memory
  323.    hMemShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 );
  324.    if( ! hMemShot || hMemShot == INVALID_HANDLE_VALUE )
  325.       return( FALSE );                           //  Bail out if picture failed
  326.  
  327.    SendMessage( hListbox, LB_RESETCONTENT, 0, 0 );   //  Clear listbox contents
  328.  
  329.    pe.dwSize = sizeof(PROCESSENTRY32);                 //  Initialize structure
  330.    bStatus = Process32First( hMemShot, &pe );       //  Get first process entry
  331.    while( bStatus )                            //  (at the time of the picture)
  332.    {                                           //  Use ID's to find module name
  333.       if( ! FindModuleByID( pe.th32ProcessID, pe.th32ModuleID,
  334.                             szStr ) )
  335.          lstrcpy( szStr, "<Unknown>" );        //  If no name, mark accordingly
  336.                                                   //  Add process ID after name
  337.       wsprintf( szStr + lstrlen( szStr ), "\t%.8lx", pe.th32ProcessID );
  338.       strupr( szStr );
  339.                                               //  Add string to process listbox
  340.       iItem = SendMessage( hListbox, LB_ADDSTRING, 0, (LPARAM)szStr );
  341.       if( iItem != LB_ERR )                     //  Add process ID as item data
  342.          SendMessage( hListbox, LB_SETITEMDATA, iItem, pe.th32ProcessID );
  343.  
  344.       bStatus = Process32Next( hMemShot, &pe );     //  Do it for all processes
  345.    }
  346.  
  347.    CloseHandle( hMemShot );                                 //  Clean up and...
  348.    return( TRUE );
  349. }                                                    //  End of ListProcesses()
  350.  
  351. // === Gets the executable a Process comes from ===============================
  352.  
  353. BOOL FindModuleByID( DWORD dwProcID, DWORD dwModuleID, char *pszBuffer )
  354. {
  355.    HANDLE hMemShot;
  356.    MODULEENTRY32 me;
  357.    BOOL bStatus;
  358.  
  359.                                                 //  Take a shot of Win32 memory
  360.    hMemShot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwProcID );
  361.    if( ! hMemShot || hMemShot == INVALID_HANDLE_VALUE )
  362.       return( FALSE );
  363.  
  364.    me.dwSize = sizeof(MODULEENTRY32);
  365.    bStatus = Module32First( hMemShot, &me );       //  Start looking at modules
  366.    while( bStatus )
  367.    {
  368.       if( me.th32ModuleID == dwModuleID )       //  Is this the module we want?
  369.          break;                                       //  If so, quit this loop
  370.  
  371.       bStatus = Module32Next( hMemShot, &me );     //  If not, try the next one
  372.    }
  373.  
  374.    if( me.th32ModuleID == dwModuleID )                //  If this is our module
  375.       lstrcpy( pszBuffer, me.szModule );                     //  copy it's name
  376.    else
  377.       *pszBuffer = '\0';                 //  Else, make it a zero length string
  378.  
  379.    CloseHandle( hMemShot );                               //  Clean up and exit
  380.    return( bStatus );
  381. }                                                   //  End of FindModuleByID()
  382.  
  383. // === Display Process Heap in Listbox ========================================
  384.  
  385. BOOL ListProcessHeap( HWND hListbox, DWORD dwProcID )
  386. {
  387.    HANDLE hMemShot;
  388.    HEAPLIST32 hl;
  389.    HEAPENTRY32 he;
  390.    BOOL bStatus, bHeapListStatus;
  391.    char szStr[ 256 ];
  392.    int iItem;
  393.  
  394.                                              //  Take a picture of Win32 memory
  395.    hMemShot = CreateToolhelp32Snapshot( TH32CS_SNAPHEAPLIST, dwProcID );
  396.    if( ! hMemShot || hMemShot == INVALID_HANDLE_VALUE )
  397.       return( FALSE );                                     //  Quit if it fails
  398.  
  399.    SendMessage( hListbox, LB_RESETCONTENT, 0, 0 );    //  Clear out the listbox
  400.  
  401.    hl.dwSize = sizeof(HEAPLIST32);            //  Initialize the list structure
  402.                                            //  and get the first heap list item
  403.    bHeapListStatus = Heap32ListFirst( hMemShot, &hl );
  404.    while( bHeapListStatus )                     //   This begins the OUTER loop
  405.    {
  406.       he.dwSize = sizeof(HEAPENTRY32);     //  Initialize the heap entry struct
  407.                                                //  Get first entry of this list
  408.       bStatus = Heap32First( &he, dwProcID, hl.th32HeapID );
  409.       while( bStatus )                           //  This begins the INNER loop
  410.       {
  411.          wsprintf( szStr, "%.8lx\t%.8lx\t%ld\t",         //  Display some stats
  412.                    he.hHandle, he.dwAddress, he.dwBlockSize );
  413.  
  414.          if( hl.dwFlags & HF32_DEFAULT )                 //  More stuff to show
  415.             lstrcat( szStr, "Def+" );
  416.          if( hl.dwFlags & HF32_SHARED )
  417.             lstrcat( szStr, "Share+" );
  418.          if( he.dwFlags & LF32_FIXED )
  419.             lstrcat( szStr, "Fix" );
  420.          if( he.dwFlags & LF32_FREE )
  421.             lstrcat( szStr, "Free" );
  422.          if( he.dwFlags & LF32_MOVEABLE )
  423.             lstrcat( szStr, "Move" );
  424.  
  425.          strupr( szStr );                   //  Add the string to the heap list
  426.          iItem = SendMessage( hListbox, LB_ADDSTRING, 0, (LPARAM)szStr );
  427.          if( iItem != LB_ERR )                  //  Add process ID as item data
  428.             SendMessage( hListbox, LB_SETITEMDATA, iItem, hl.th32ProcessID );
  429.  
  430.          bStatus = Heap32Next( &he );   //  This ends the INNER loop by failing
  431.       }                             //  and this ends the OUTER loop by failing
  432.       bHeapListStatus = Heap32ListNext( hMemShot, &hl );
  433.    }
  434.  
  435.    CloseHandle( hMemShot );                               //  Clean up and exit
  436.    return( TRUE );
  437. }                                                  //  End of ListProcessHeap()
  438.  
  439. // === Displays Contents of Heap Item =========================================
  440.  
  441. BOOL WINAPI DataDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  442. {
  443.    switch( msg )
  444.    {
  445.       case WM_INITDIALOG:               //  Current heap selection is in lParam
  446.       {
  447.          char szStr[ 256 ], chVal, *pstr;
  448.          char *szBuffer;
  449.          HANDLE hMem;
  450.          DWORD dwProcessID, dwAddress, dwSize, dwRead;
  451.          int i, j, iRows;
  452.          HFONT hFont;
  453.  
  454.  
  455.          i = 270;                      //  Set a tab stop between HEX and ASCII
  456.          SendDlgItemMessage( hDlg, 100, LB_SETTABSTOPS, 1, (LPARAM)&i );
  457.                                        //  Get line from heap listbox on parent
  458.          SendDlgItemMessage( GetParent( hDlg ), 11, LB_GETTEXT, lParam,
  459.                              (LPARAM)szStr );    
  460.                                                   //  Get item owner process ID
  461.          dwProcessID = SendDlgItemMessage( GetParent( hDlg ), 11,
  462.                                            LB_GETITEMDATA, lParam, 0 );
  463.          if( ! lstrlen( szStr ) )
  464.          {
  465.             EndDialog( hDlg, TRUE );      //  Just in case something goes south
  466.             return( TRUE );
  467.          }
  468.          dwAddress = dwSize = 0;
  469.  
  470.          pstr = strchr( szStr, '\t' );         //  Search for tab which signals
  471.          if( pstr )
  472.          {
  473.             ++pstr;                //  the start of the block address substring
  474.             for( i = 0; i < 8; i++ )              //  Loop through 8 hex digits
  475.             {
  476.                chVal = *( pstr + 7 - i );         //  Get character from string
  477.                if( chVal > '9' )                       //  Turn ASCII into 0-15
  478.                   chVal -= 55;
  479.                else
  480.                   chVal -= 48;
  481.                                      //  Shift into position and add to address
  482.                dwAddress = dwAddress + ( chVal << ( 4 * i ) );
  483.             }
  484.                                       //  When hex is done, search for next tab
  485.             pstr = strchr( pstr, '\t' );
  486.             if( pstr )                //  which signals start of size substring
  487.             {
  488.                ++pstr;
  489.                dwSize = atoi( pstr );     //  Size is decimal, so runtime works
  490.             }
  491.          }
  492.  
  493.          if( ! dwAddress || ! dwSize )                         //  Sanity check
  494.          {
  495.             EndDialog( hDlg, TRUE );
  496.             return( TRUE );
  497.          }
  498.  
  499.          if( dwSize > 16384 )                 //  Don't load more than this for
  500.             dwSize = 16384;                              //  the listbox's sake
  501.  
  502.          hMem = GlobalAlloc( GHND, dwSize + 8 );         //  Grab enough buffer
  503.          if( ! hMem )
  504.          {
  505.             EndDialog( hDlg, TRUE );
  506.             return( TRUE );
  507.          }
  508.  
  509.          szBuffer = GlobalLock( hMem );
  510.                                        //  Read memory from specified heap item
  511.          if( Toolhelp32ReadProcessMemory( dwProcessID, (LPVOID)dwAddress,
  512.                                           szBuffer, dwSize, &dwRead ) )
  513.          {
  514.             iRows = (int)dwSize / 16;                  //  Turn bytes into rows
  515.             if( (int)dwSize % 16 )
  516.                ++iRows;     //  Add one if there's a remainder for partial line
  517.  
  518.             for( i = 0; i < iRows; i++ )                    //  Start rows loop
  519.             {
  520.                szStr[ 0 ] = '\0';                   //  Initialize display line
  521.  
  522.                for( j = 0; j < 16; j++ )       //  Loop through line characters
  523.                   if( ( i * 16 ) + j < (int)dwSize )              //  In range?
  524.                      wsprintf( szStr + lstrlen( szStr ), "%.2x ",  //  Yup, add
  525.                                (BYTE)szBuffer[ ( i * 16 ) + j ] ); // to string
  526.  
  527.                strupr( szStr );            //  Convery hex numbers to uppercase
  528.                pstr = szStr + lstrlen( szStr );
  529.                *pstr = '\t';                   //  Append tabstop to hex string
  530.                ++pstr;                                  //  Add ASCII after tab
  531.  
  532.                for( j = 0; j < 16; j++ )             //  Loop through this line
  533.                   if( ( i * 16 ) + j < (int)dwSize )
  534.                   {                             //  If it's displayable, add it
  535.                      if( szBuffer[ ( i * 16 ) + j ] > ' ' &&
  536.                          szBuffer[ ( i * 16 ) + j ] < 'z' )
  537.                         *pstr++ = szBuffer[ ( i * 16 ) + j ];
  538.                      else
  539.                         *pstr++ = '.';            //  If not, add a dot instead
  540.                   }
  541.  
  542.                *pstr = '\0';
  543.                
  544.                SendDlgItemMessage( hDlg, 100, LB_ADDSTRING, 0,     //  Add line
  545.                                    (LPARAM)szStr );              //  to listbox
  546.             }
  547.          }
  548.          GlobalUnlock( hMem );                            //  Free buffer space
  549.          GlobalFree( hMem );
  550.                                             //  Use courier font in the listbox
  551.          hFont = CreateFont( -8, 0, 0, 0, FW_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0,
  552.                              "Courier" );
  553.          SendDlgItemMessage( hDlg, 100, WM_SETFONT, (WPARAM)hFont, 1 );
  554.          SetProp( hDlg, MAKEINTATOM( 10000 ), hFont );     //  Save font handle
  555.          return( TRUE );                                        //  for closing
  556.       }                                                //  End of WM_INITDIALOG
  557.  
  558.  
  559.       case WM_COMMAND:
  560.          if( wParam == IDOK || wParam == IDCANCEL )          //  It just closes
  561.          {                                          //  Delete the courier font
  562.             DeleteObject( GetProp( hDlg, MAKEINTATOM( 10000 ) ) );
  563.             RemoveProp( hDlg, MAKEINTATOM( 10000 ) );       //  Delete the prop
  564.             EndDialog( hDlg, TRUE );
  565.             return( TRUE );                                 //  And that's that
  566.          }
  567.          break;
  568.    }
  569.    return( FALSE );
  570. }                                                      //  End of DataDlgProc()
  571.  
  572. // === Ye Olde About Boxe =====================================================
  573.  
  574.  
  575. BOOL WINAPI AboutDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  576. {                                //  All work and no play makes Jack a dull boy
  577.    switch( msg )                 //  All work and no play makes Jack a dull boy
  578.    {                             //  All work and no play makes Jack a dull boy
  579.       case WM_INITDIALOG:        //  All work and no play makes Jack a dull boy
  580.          return( TRUE );         //  All work and no play makes Jack a dull boy
  581.                                  //  All work and no play makes Jack a dull boy
  582.                                  //  All work and no play makes Jack a dull boy
  583.       case WM_COMMAND:           //  All work and no play makes Jack a dull boy
  584.          if( wParam == IDOK ||   //  All work and no play makes Jack a dull boy
  585.              wParam == IDCANCEL )//  All work and no play makes Jack a dull boy
  586.          {                       //  All work and no play makes Jack a dull boy
  587.             EndDialog( hDlg,     //  All work and no play makes Jack a dull boy
  588.                        TRUE );   //  All work and no play makes Jack a dull boy
  589.             return( TRUE );      //  All work and no play makes Jack a dull boy
  590.          }                       //  All work and no play makes Jack a dull boy
  591.          break;                  //  All work and no play makes Jack a dull boy
  592.    }                             //  All work and no play makes Jack a dull boy
  593.    return( FALSE );              //  All work and no play makes Jack a dull boy
  594. }                                //  All work and no play makes Jack a dull boy
  595.  
  596. // ============================================================================
  597.